/*-------------------------------------------------------------------------
 *
 * pg_constraint.h
 *	  "约束" 系统目录 (pg_constraint) 的定义
 *
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/catalog/pg_constraint.h
 *
 * NOTES
 *	  Catalog.pm 模块读取此文件并推导模式
 *	  信息。
 *
 *-------------------------------------------------------------------------
 */
#ifndef PG_CONSTRAINT_H
#define PG_CONSTRAINT_H

#include "catalog/dependency.h"
#include "catalog/genbki.h"
#include "catalog/pg_constraint_d.h"
#include "nodes/pg_list.h"

/* ----------------
 *		pg_constraint 定义。 cpp 将其转换为
 *		typedef struct FormData_pg_constraint
 * ----------------
 */
CATALOG(pg_constraint,2606,ConstraintRelationId)
{
	Oid			oid;			/* oid */

	/*
	 * conname + connamespace 有意未唯一；我们允许，例如，
	 * 对不同关系的约束使用相同的名称。这部分是为了与过去
	 * Postgres 实践的向后兼容，部分是因为我们不想为了
	 * 生成无名约束的全局唯一名称而必须获得全局锁。
	 * 我们仅为 SQL 规范兼容性而将命名空间与约束名称关联。
	 *
	 * 然而，我们确实要求 conname 在单个关系或域的约束中是唯一的。
	 * 这通过 conrelid + contypid + conname 的唯一索引来强制执行。
	 */
	NameData	conname;		/* 此约束的名称 */
	Oid			connamespace BKI_LOOKUP(pg_namespace);	/* 包含约束的命名空间的 OID */
	char		contype;		/* 约束类型；见下面的代码 */
	bool		condeferrable;	/* 可延迟约束？ */
	bool		condeferred;	/* 默认延迟？ */
	bool		convalidated;	/* 约束已被验证？ */

	/*
	 * conrelid 和 conkey 仅在约束适用于特定关系时有意义
	 * （这排除了域约束和声明）。否则 conrelid 为 0，conkey 为 NULL。
	 */
	Oid			conrelid BKI_LOOKUP_OPT(pg_class);	/* 此约束限制的关系 */

	/*
	 * 如果这是域约束，contypid 链接到域的 pg_type 行。
	 * 否则为 0。
	 *
	 * 对于 SQL 风格的全局 ASSERTION，两者 conrelid 和 contypid
	 * 都是零。然而当前不支持此功能。
	 */
	Oid			contypid BKI_LOOKUP_OPT(pg_type);	/* 此约束限制的域 */

	/*
	 * conindid 链接到支持该约束的索引（如果有）；否则为 0。
	 * 这用于唯一、主键和排除约束，以及更不明显的外键约束 
	 * （其中索引是被引用关系的被引用列上的唯一索引）。
	 * 请注意，在第一种情况下，索引是 conrelid，但在第二种情况下是 confrelid。
	 */
	Oid			conindid BKI_LOOKUP_OPT(pg_class);	/* 支持此约束的索引 */

	/*
	 * 如果该约束为从分区表继承的分区，则这是对应的父约束的 OID。
	 */
	Oid			conparentid BKI_LOOKUP_OPT(pg_constraint);

	/*
	 * 这些字段，加上 confkey，仅对外键约束有意义。
	 * 否则 confrelid 为 0，字符字段为空格。
	 */
	Oid			confrelid BKI_LOOKUP_OPT(pg_class); /* 外键引用的关系 */
	char		confupdtype;	/* 外键的 ON UPDATE 操作 */
	char		confdeltype;	/* 外键的 ON DELETE 操作 */
	char		confmatchtype;	/* 外键的匹配类型 */

	/* 有本地定义（因此，当 coninhcount 为 0 时，不应删除） */
	bool		conislocal;

	/* 从直接父关系继承的次数 */
	int32		coninhcount;

	/* 有本地定义且不能被继承 */
	bool		connoinherit;

#ifdef CATALOG_VARLEN			/* 可变长度字段从这里开始 */

	/*
	 * 约束适用的 conrelid 的列，如果已知（触发器约束为 NULL）
	 */
	int16		conkey[1];

	/*
	 * 如果是外键，则为 confrelid 的引用列
	 */
	int16		confkey[1];

	/*
	 * 如果是外键，则为约束每列的 PK = FK 等式运算符的 OID
	 */
	Oid			conpfeqop[1] BKI_LOOKUP(pg_operator);

	/*
	 * 如果是外键，则为约束每列的 PK = PK 等式运算符的 OID
	 * （即引用列的等式）
	 */
	Oid			conppeqop[1] BKI_LOOKUP(pg_operator);

	/*
	 * 如果是外键，则为约束每列的 FK = FK 等式运算符的 OID
	 * （即引用列的等式）
	 */
	Oid			conffeqop[1] BKI_LOOKUP(pg_operator);

	/*
	 * 如果是具有 ON DELETE SET NULL/DEFAULT 操作的外键，则为
	 * 要更新的 conkey 的子集。如果为空，则更新所有列。
	 */
	int16		confdelsetcols[1];

	/*
	 * 如果是排除约束，则该约束每一列的排除操作符的 OID
	 */
	Oid			conexclop[1] BKI_LOOKUP(pg_operator);

	/*
	 * 如果是检查约束，nodeToString 表达式的表示
	 */
	pg_node_tree conbin;
#endif
} FormData_pg_constraint;

/* ----------------
 *		Form_pg_constraint 对应于一个指向具有
 *		pg_constraint 关系格式的元组的指针。
 * ----------------
 */
typedef FormData_pg_constraint *Form_pg_constraint;

DECLARE_TOAST(pg_constraint, 2832, 2833);

DECLARE_INDEX(pg_constraint_conname_nsp_index, 2664, ConstraintNameNspIndexId, on pg_constraint using btree(conname name_ops, connamespace oid_ops));
DECLARE_UNIQUE_INDEX(pg_constraint_conrelid_contypid_conname_index, 2665, ConstraintRelidTypidNameIndexId, on pg_constraint using btree(conrelid oid_ops, contypid oid_ops, conname name_ops));
DECLARE_INDEX(pg_constraint_contypid_index, 2666, ConstraintTypidIndexId, on pg_constraint using btree(contypid oid_ops));
DECLARE_UNIQUE_INDEX_PKEY(pg_constraint_oid_index, 2667, ConstraintOidIndexId, on pg_constraint using btree(oid oid_ops));
DECLARE_INDEX(pg_constraint_conparentid_index, 2579, ConstraintParentIndexId, on pg_constraint using btree(conparentid oid_ops));

/* 如果使用了整个行的 Var，conkey 可能包含零（InvalidAttrNumber） */
DECLARE_ARRAY_FOREIGN_KEY_OPT((conrelid, conkey), pg_attribute, (attrelid, attnum));
DECLARE_ARRAY_FOREIGN_KEY((confrelid, confkey), pg_attribute, (attrelid, attnum));

#ifdef EXPOSE_TO_CLIENT_CODE

/* contype 的有效值 */
#define CONSTRAINT_CHECK			'c'
#define CONSTRAINT_FOREIGN			'f'
#define CONSTRAINT_PRIMARY			'p'
#define CONSTRAINT_UNIQUE			'u'
#define CONSTRAINT_TRIGGER			't'
#define CONSTRAINT_EXCLUSION		'x'

/*
 * confupdtype 和 confdeltype 的有效值为 parsenodes.h 中定义的 FKCONSTR_ACTION_xxx 常量。
 * confmatchtype 的有效值为 parsenodes.h 中定义的 FKCONSTR_MATCH_xxx 常量。
 */

#endif							/* EXPOSE_TO_CLIENT_CODE */

/*
 * 确定约束类型以便查找
 */
typedef enum ConstraintCategory
{
	CONSTRAINT_RELATION,
	CONSTRAINT_DOMAIN,
	CONSTRAINT_ASSERTION		/* 用于未来扩展 */
} ConstraintCategory;


extern Oid	CreateConstraintEntry(const char *constraintName,
								  Oid constraintNamespace,
								  char constraintType,
								  bool isDeferrable,
								  bool isDeferred,
								  bool isValidated,
								  Oid parentConstrId,
								  Oid relId,
								  const int16 *constraintKey,
								  int constraintNKeys,
								  int constraintNTotalKeys,
								  Oid domainId,
								  Oid indexRelId,
								  Oid foreignRelId,
								  const int16 *foreignKey,
								  const Oid *pfEqOp,
								  const Oid *ppEqOp,
								  const Oid *ffEqOp,
								  int foreignNKeys,
								  char foreignUpdateType,
								  char foreignDeleteType,
								  const int16 *fkDeleteSetCols,
								  int numFkDeleteSetCols,
								  char foreignMatchType,
								  const Oid *exclOp,
								  Node *conExpr,
								  const char *conBin,
								  bool conIsLocal,
								  int conInhCount,
								  bool conNoInherit,
								  bool is_internal);

extern void RemoveConstraintById(Oid conId);
extern void RenameConstraintById(Oid conId, const char *newname);

extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId,
								 const char *conname);
extern bool ConstraintNameExists(const char *conname, Oid namespaceid);
extern char *ChooseConstraintName(const char *name1, const char *name2,
								  const char *label, Oid namespaceid,
								  List *others);

extern void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
									  Oid newNspId, bool isType, ObjectAddresses *objsMoved);
extern void ConstraintSetParentConstraint(Oid childConstrId,
										  Oid parentConstrId,
										  Oid childTableId);
extern Oid	get_relation_constraint_oid(Oid relid, const char *conname, bool missing_ok);
extern Bitmapset *get_relation_constraint_attnos(Oid relid, const char *conname,
												 bool missing_ok, Oid *constraintOid);
extern Oid	get_domain_constraint_oid(Oid typid, const char *conname, bool missing_ok);
extern Oid	get_relation_idx_constraint_oid(Oid relationId, Oid indexId);

extern Bitmapset *get_primary_key_attnos(Oid relid, bool deferrableOk,
										 Oid *constraintOid);
extern void DeconstructFkConstraintRow(HeapTuple tuple, int *numfks,
									   AttrNumber *conkey, AttrNumber *confkey,
									   Oid *pf_eq_oprs, Oid *pp_eq_oprs, Oid *ff_eq_oprs,
									   int *num_fk_del_set_cols, AttrNumber *fk_del_set_cols);

extern bool check_functional_grouping(Oid relid,
									  Index varno, Index varlevelsup,
									  List *grouping_columns,
									  List **constraintDeps);

#endif							/* PG_CONSTRAINT_H */
